package com.seanzx.dp.condition;

import com.seanzx.dp.entity.Column;

import java.util.ArrayList;
import java.util.List;

public class ConditionNode {
    private boolean isRoot = false;
    private Condition condition;
    private ConditionNode parentNode;
    private final List<ConditionNode> childNodes = new ArrayList<>();

    public boolean test(List<Column> columns, List<String> values) {
        if (!isRoot) {
            // check condition of current node, skip root node because it's always true.
            Column column = columns.stream().filter(c -> c.getName().equals(condition.getColumnName())).findFirst().get();
            String value = values.get(column.getIndex());
            if (!condition.test(value)) {
                return false;
            }
        }
        // if current node has no child node or has child nodes that are true, current node is also true.
        // else if all the child nodes is false, current node is false.
        if (childNodes.isEmpty()) {
            return true;
        }
        for (ConditionNode childNode : childNodes) {
            if (childNode.test(columns, values)) {
                return true;
            }
        }
        return false;
    }

    public ConditionNode(String columnName, ConditionType conditionType, List<String> values) {
        condition = new Condition();
        condition.setColumnName(columnName);
        condition.setConditionType(conditionType);
        condition.setValues(values);
    }

    public ConditionNode(String columnName) {
        condition = new Condition();
        condition.setColumnName(columnName);
    }

    public void setConditionType(ConditionType conditionType) {
        condition.setConditionType(conditionType);
    }

    public void setValues(List<String> values) {
        condition.setValues(values);
    }

    private ConditionNode() {
        isRoot = true;
    }

    public void and(ConditionNode node) {
        node.parentNode = this;
        childNodes.add(node);
    }

    public void or(ConditionNode node) {
        node.parentNode = this.parentNode;
        this.parentNode.childNodes.add(node);
    }

    public static ConditionNode rootNode() {
        return new ConditionNode();
    }
}
